#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>

#define MAX_CLIENTS 10      // 最大客户端连接数
#define BUFFER_SIZE 1024    // 消息缓冲区大小（字节）
#define NAME_SIZE 50        // 用户名最大长度（字节）

// 客户端信息结构体
typedef struct {
    int socket;                     // 客户端的套接字句柄（用于网络通信）
    char name[NAME_SIZE];           // 存放用户名字
    int active;                     // 存放用户的状态
} Client;

Client clients[MAX_CLIENTS];        // 存储所有连接的客户端
int client_count = 0;               // 判断当前客户端的在线数量
pthread_mutex_t clients_mutex;      // 多线程时保证数据安全的互斥锁

// 广播消息给所有客户端（除了发送者）
void broadcast_message(const char* message, size_t sender_index) {
    pthread_mutex_lock(&clients_mutex);  // 加锁保护客户端数组

    for (int i = 0; i < MAX_CLIENTS; i++) {
        if (clients[i].active && i != sender_index) {
            send(clients[i].socket, message, strlen(message), 0);
        }
    }
    
    pthread_mutex_unlock(&clients_mutex);  // 解锁
}

// 处理客户端的线程函数
void* handle_client(void* arg) {
    int client_index = *(int*)arg;   // 从参数中获取客户端索引
    free(arg);  // 释放动态分配的内存

    char buffer[BUFFER_SIZE];       // 接收客户端消息的缓冲区
    int bytes_read;                 // 接收的字节数

    char message[BUFFER_SIZE + NAME_SIZE + 4];  // 消息缓冲区，包含用户名

    // 第一步：接收客户端发送的用户名
    if ((bytes_read = recv(clients[client_index].socket, clients[client_index].name, NAME_SIZE - 1, 0)) <= 0) {
        printf("接收用户名失败或客户端断开连接\n");
        close(clients[client_index].socket);  // 关闭套接字

        pthread_mutex_lock(&clients_mutex);    // 加锁
        clients[client_index].active = 0;      // 标记客户端为离线
        client_count--;
        pthread_mutex_unlock(&clients_mutex);  // 解锁

        return NULL;
    }

    // 确保用户名以null结尾
    clients[client_index].name[bytes_read] = '\0';
    // 移除可能的换行符
    if (clients[client_index].name[strlen(clients[client_index].name) - 1] == '\n') {
        clients[client_index].name[strlen(clients[client_index].name) - 1] = '\0';
    }

    printf("%s 加入聊天室\n", clients[client_index].name);

    // 广播用户加入消息
    snprintf(message, sizeof(message), "%s 加入了聊天室\n", clients[client_index].name);
    broadcast_message(message, client_index);

    // 接收并广播消息
    while ((bytes_read = recv(clients[client_index].socket, buffer, BUFFER_SIZE - 1, 0)) > 0) {
        // 确保消息以null结尾
        buffer[bytes_read] = '\0';
        // 移除可能的换行符
        if (buffer[strlen(buffer) - 1] == '\n') {
            buffer[strlen(buffer) - 1] = '\0';
        }

        // 检查是否退出
        if (strncmp(buffer, "exit", 4) == 0) {
            break;
        }

        // 格式化消息（包含用户名）
        snprintf(message, sizeof(message), "%s: %s\n", clients[client_index].name, buffer);
        printf("%s", message);

        // 广播消息
        broadcast_message(message, client_index);
    }

    // 客户端断开连接
    printf("%s 离开了聊天室\n", clients[client_index].name);

    // 广播用户离开消息
    snprintf(message, sizeof(message), "%s 离开了聊天室\n", clients[client_index].name);
    broadcast_message(message, client_index);

    // 清理客户端
    close(clients[client_index].socket);

    pthread_mutex_lock(&clients_mutex);
    clients[client_index].active = 0;
    client_count--;
    pthread_mutex_unlock(&clients_mutex);

    return NULL;
}

int main(int argc, char* argv[]) {
    int server_socket, new_socket;       // 服务器套接字、新客户端套接字
    struct sockaddr_in server_addr, client_addr;    // 服务器/客户端地址结构
    int port;
    socklen_t addr_len = sizeof(struct sockaddr_in);  // 地址结构大小
    pthread_t thread;                  // 线程ID
    int* client_index_ptr;             // 客户端索引的指针

    // 检查命令行参数
    if (argc != 2) {
        fprintf(stderr, "用法: %s <端口号>\n", argv[0]);
        return 1;
    }

    port = atoi(argv[1]);       // 将命令行参数的字符串端口转为整数

    // 初始化客户端数组：所有客户端默认设为"离线"状态
    for (int i = 0; i < MAX_CLIENTS; i++) {
        clients[i].socket = -1;  // 无效套接字
        clients[i].name[0] = '\0'; // 空用户名
        clients[i].active = 0;    // 不活跃
    }

    // 初始化互斥锁（用于多线程同步）
    if (pthread_mutex_init(&clients_mutex, NULL) != 0) {
        perror("互斥锁初始化失败");
        return 1;
    }

    // 创建服务器用于监听连接的套接字
    if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("创建socket失败");
        return 1;
    }

    // 设置服务器地址
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(port);

    // 设置套接字选项，允许端口重用
    int opt = 1;
    if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
        perror("setsockopt失败");
        close(server_socket);
        return 1;
    }

    // 绑定socket到端口
    if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        perror("绑定失败");
        close(server_socket);
        return 1;
    }

    // 监听连接
    if (listen(server_socket, 3) == -1) {
        perror("监听失败");
        close(server_socket);
        return 1;
    }

    printf("聊天室服务器已启动，端口: %d\n", port);
    printf("等待客户端连接...\n");

    // 接受客户端连接
    while (1) {
        if ((new_socket = accept(server_socket, (struct sockaddr*)&client_addr, &addr_len)) == -1) {
            perror("接受连接失败");
            continue;
        }

        pthread_mutex_lock(&clients_mutex);

        // 查找空闲客户端槽位
        int client_index = -1;
        for (int i = 0; i < MAX_CLIENTS; i++) {
            if (!clients[i].active) {
                client_index = i;
                break;
            }
        }

        // 检查是否还有空间
        if (client_index == -1) {
            printf("客户端已满，拒绝连接\n");
            close(new_socket);
            pthread_mutex_unlock(&clients_mutex);
            continue;
        }

        // 添加客户端
        clients[client_index].socket = new_socket;
        clients[client_index].active = 1;
        client_count++;

        printf("新客户端连接，当前在线: %d\n", client_count);

        pthread_mutex_unlock(&clients_mutex);

        // 创建处理客户端的线程
        client_index_ptr = (int*)malloc(sizeof(int));
        if (client_index_ptr == NULL) {
            perror("内存分配失败");
            close(new_socket);
            continue;
        }

        *client_index_ptr = client_index;

        // 创建线程
        if (pthread_create(&thread, NULL, handle_client, client_index_ptr) != 0) {
            perror("创建线程失败");
            close(new_socket);
            free(client_index_ptr);
            pthread_mutex_lock(&clients_mutex);
            clients[client_index].active = 0;
            client_count--;
            pthread_mutex_unlock(&clients_mutex);
        } else {
            pthread_detach(thread);  // 分离线程，自动释放资源
        }
    }

    // 清理
    pthread_mutex_destroy(&clients_mutex);
    close(server_socket);
    return 0;
}
